package com.bluexmicro.android.upgradebox.screen.upgrade

import android.Manifest
import android.bluetooth.le.ScanResult
import android.content.Context
import android.content.pm.PackageManager
import android.text.TextUtils
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey
import com.bluexmicro.android.ota.OtaParamHelper
import com.bluexmicro.android.upgradebox.screen.configure.Resource
import com.bluexmicro.android.upgradebox.screen.configure.dataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import java.io.File
import java.math.BigInteger


class LocalDataUseCase {

    private val resourcesKey = stringSetPreferencesKey("resources")
    private val nameFilterKey = stringSetPreferencesKey("nameFilter")
    private val macFilterKey = stringSetPreferencesKey("macFilter")
    private val companyFilterKey = stringSetPreferencesKey("companyFilter")
    private val rssiFilterKey = intPreferencesKey("rssiFilter")

    var resources = emptyList<Resource>()

    private var nameFilters = emptyList<String>()
    private var companyIdFilters = emptyList<String>()
    private var macFilters = emptyList<String>()
    private var rssiThreshold = -127 // -127~0

    /**
     * 加载过滤条件
     */
    suspend fun loadLocalData(context: Context) {
        val dataStore = context.dataStore
        val res = loadResourcesFlow(dataStore).first()

        val names = loadNameFilterFlow(dataStore).first()
        val company = loadCompanyFilterFlow(dataStore).first()
        val macList = loadMacFiltersFlow(dataStore).first()
        val rssi = loadRssiThresholdFlow(dataStore).first() - 127

        //先加载数据避免每次都重复读取文件数据
        res.forEach { resource ->
            OtaParamHelper.loadBinData(resource.file)?.let {
                resource.rawData = it
            }
        }
        resources = res
        nameFilters = names
        companyIdFilters = company
        macFilters = macList
        rssiThreshold = rssi
    }

    fun isTarget(scanResult: ScanResult, context: Context): Boolean {
        val nameMatches = if (nameFilters.isEmpty()) {
            true
        } else {
            val deviceName = if (ActivityCompat.checkSelfPermission(
                    context,
                    Manifest.permission.BLUETOOTH_CONNECT
                ) == PackageManager.PERMISSION_GRANTED
            ) {
                if (TextUtils.isEmpty(scanResult.device.name)) "" else scanResult.device.name
            } else ""
            val localName = scanResult.scanRecord?.deviceName ?: ""
            var matches = false
            for (nameFilter in nameFilters) {
//                Log.w("TAG", "isTarget: $deviceName")
//                Log.d("TAG", "isTarget: $localName")
//                Log.e("TAG", "isTarget: $nameFilter")
                if (deviceName.contains(nameFilter, true) || localName.contains(nameFilter, true)) {
                    matches = true
                    break
                }
            }
//            Log.e("TAG", "matches: $matches" )
            matches
        }
        val rssiMatches = scanResult.rssi >= rssiThreshold

        val macMatches = if (macFilters.isEmpty()) {
            true
        } else {
            var matches = false
            for (macFilter in macFilters) {
                if (scanResult.device.address.contains(macFilter, true)) {
                    matches = true
                    break
                }
            }
            matches
        }

        val companyMatches = if (companyIdFilters.isEmpty()) {
            true
        } else {
            var matches = false
            for (companyIdFilter in companyIdFilters) {
                val companyId = companyIdFilter.toInt(16)

                if (scanResult.scanRecord?.getManufacturerSpecificData(companyId) != null) {
                    matches = true
                    break
                }
            }
            matches
        }
        return nameMatches && rssiMatches && macMatches && companyMatches
    }

    private fun loadResourcesFlow(dataStore: DataStore<Preferences>): Flow<List<Resource>> =
        dataStore.data.map {
            val sets = mutableListOf<Resource>()
            it[resourcesKey]?.forEach { formatRes ->
                //"path|hexAddress?"
                val params = formatRes.split('|')
                val file = if (0 in params.indices) {
                    File(params[0])
                } else {
                    null
                }
                val address = if (1 in params.indices) {
                    try {
                        BigInteger(params[1], 16)
                    } catch (e: Exception) {
                        e.printStackTrace()
                        null
                    }
                } else {
                    null
                }
                if (file != null) {
                    sets.add(Resource(file, address))
                }
            }
            sets
        }

    private fun loadCompanyFilterFlow(dataStore: DataStore<Preferences>): Flow<List<String>> =
        dataStore.data.map {
            val sets = mutableListOf<String>()
            it[companyFilterKey]?.forEach { companyIdHex ->
                //todo 有效性检查
                sets.add(companyIdHex)
            }
            sets
        }

    private fun loadNameFilterFlow(dataStore: DataStore<Preferences>): Flow<List<String>> =
        dataStore.data.map {
            val sets = mutableListOf<String>()
            it[nameFilterKey]?.forEach { name ->
                sets.add(name)
            }
            sets
        }

    private fun loadMacFiltersFlow(dataStore: DataStore<Preferences>): Flow<List<String>> =
        dataStore.data.map {
            val sets = mutableListOf<String>()
            it[macFilterKey]?.forEach { mac ->
                sets.add(mac)
            }
            sets
        }

    /**
     * [0,127]
     */
    private fun loadRssiThresholdFlow(dataStore: DataStore<Preferences>): Flow<Int> =
        dataStore.data.map {
            it[rssiFilterKey] ?: 0
        }

}

